#include "stdafx.h"
namespace comms{
void cLog_Warning(const char* mask,...){
	FILE* F=fopen("log.txt","a");
	if(F){
		va_list args;
		va_start(args,mask);		
		vfprintf(F,mask,args);
		va_end(args);
		fclose(F);
	}
}
void cLog_Message(const char* mask,...){
	FILE* F=fopen("log.txt","a");
	if(F){
		va_list args;
		va_start(args,mask);		
		vfprintf(F,mask,args);
		va_end(args);
		fclose(F);
	}
}

//-----------------------------------------------------------------------------
// cMeshConatainer::IsValid
//-----------------------------------------------------------------------------
bool cMeshConatainer::IsValid(const bool ShowWarning /*= true*/) const {	

	return true;
} // cMeshConatainer::IsValid

//-----------------------------------------------------------------------------
// cMeshConatainer::Clear
//-----------------------------------------------------------------------------
void cMeshConatainer::Clear() {
	m_Positions.Clear();
	m_TexCoords.Clear();
	m_Normals.Clear();
	m_Tangents.Clear();
	m_Raw.Clear();
	m_Name.Clear();
} // cMeshConatainer::Clear

//-----------------------------------------------------------------------------
// cMeshConatainer::GetPolyCount
//-----------------------------------------------------------------------------
int cMeshConatainer::GetPolyCount() const {
	int Count = 0;
	int index = 0;
	while(index < m_Raw.Count()) {
		index += m_Raw[index][0] + 1;
		Count++;
	}
	return Count;
} // cMeshConatainer::GetPolyCount

//-----------------------------------------------------------------------------
// cMeshConatainer::IsTriangulated
//-----------------------------------------------------------------------------
bool cMeshConatainer::IsTriangulated() const {
	int index = 0;
	while(index < m_Raw.Count()) {
		const int D = m_Raw[index][0];
		if(D != 3) {
			return false;
		}
		index += D + 1;
	}
	return true;
} // cMeshConatainer::IsTriangulated

//-----------------------------------------------------------------------------
// cMeshConatainer::Triangulate
//-----------------------------------------------------------------------------
void cMeshConatainer::Triangulate(cList<cVec3i> &TriRaw) const {
	TriRaw.Clear();
	int index = 0;
	while(index < m_Raw.Count()) {
		int nDeg = m_Raw[index][0];
		const int idMtl = m_Raw[index][1];
		if(nDeg < 3) {
			// Skip lines and points.
			index += nDeg + 1;
		} else {
			const cVec3i i0 = m_Raw[++index];
			nDeg -= 2;
			while(nDeg--) {
				index++;
				TriRaw.Add(cVec3i(3, idMtl, 0));
				TriRaw.Add(i0);
				TriRaw.Add(m_Raw[index]);
				TriRaw.Add(m_Raw[index + 1]);
			}
			index += 2;
		}
	}
} // cMeshConatainer::Triangulate

// cMeshConatainer::Triangulate

//-----------------------------------------------------------------------------
// cMeshConatainer::Triangulate
//-----------------------------------------------------------------------------
void cMeshConatainer::Triangulate() {
	if(IsTriangulated()) {
		return;
	}
	cList<cVec3i> TriRaw;
	Triangulate(TriRaw);
	m_Raw.Copy(TriRaw);
} // cMeshConatainer::Triangulate

//-----------------------------------------------------------------------------
// cMeshConatainer::InvertRaw
//-----------------------------------------------------------------------------
void cMeshConatainer::InvertRaw() {
	int index = 0;
	while(index < m_Raw.Count()) {
		const int Deg = m_Raw[index][0];
		int i = 0;
		while(i < Deg / 2) {
			cMath::Swap(m_Raw[index + 1 + i], m_Raw[index + Deg - i]);
			i++;
		}
		index += Deg + 1;
	}
} // cMeshConatainer::InvertRaw

//-----------------------------------------------------------------------------
// cMeshConatainer::CalcNormals
//-----------------------------------------------------------------------------
void cMeshConatainer::CalcNormals() {
	m_Normals.Clear();

	if(m_Positions.Count() < 1) { // No vertices.
		return;
	}

	m_Normals.SetCount(m_Positions.Count(), cVec3::Zero);

	// Pointing raw to newly created normals:
	int index = 0;
	while(index < m_Raw.Count()) {
		int nDeg = m_Raw[index][0];
		while(nDeg--) {
			index++;
			m_Raw[index][2] = m_Raw[index][0];
		}
		index++;
	}

	// Calcing normals:
	index = 0;
	while(index < m_Raw.Count()) {
		const int nDeg = m_Raw[index][0];
		if(nDeg >= 3) { // Skip lines and points.
			cVec3 c(0,0,0);
			for(int i=0;i<nDeg;i++){
				c+=m_Positions[m_Raw[index+i+1][0]];
			}
			c/=nDeg;
			for(int i=0;i<nDeg;i++){
				cVec3 pc=m_Positions[m_Raw[index+i+1][0]];
				cVec3 pn=m_Positions[m_Raw[index+((i+1)%nDeg)+1][0]];
				pc-=c;
				pn-=c;
				const cVec3 Normal = cVec3::Cross(pc,pn);
				m_Normals[m_Raw[index+i+1][0]] += Normal;
			}
			
		}
		index += nDeg + 1;
	}

	// Normalizing normals:
	for(int i = 0; i < m_Normals.Count(); i++) {
		m_Normals[i].NormalizeSafe();
	}
} // cMeshConatainer::CalcNormals

//*****************************************************************************
// GenPlane
//*****************************************************************************

//-----------------------------------------------------------------------------
// cMeshConatainer::PlaneArgs::SetDefaults
//-----------------------------------------------------------------------------
void cMeshConatainer::PlaneArgs::SetDefaults() {
	Width = 1.0f;
	Height = 1.0f;
	wSubDivs = 10;
	hSubDivs = 10;
	Axis = cVec3::AxisY;
	TwoSided = false;
} // cMeshConatainer::PlaneArgs::SetDefaults

//-----------------------------------------------------------------------------
// cMeshConatainer::PlaneArgs::Validate
//-----------------------------------------------------------------------------
void cMeshConatainer::PlaneArgs::Validate() {
	const PlaneArgs Defs;
	if(Width < cMath::SpaceEpsilon) {
		Width = Defs.Width;
	}
	if(Height < cMath::SpaceEpsilon) {
		Height = Defs.Height;
	}
	if(wSubDivs < 1) {
		wSubDivs = Defs.wSubDivs;
	}
	if(hSubDivs < 1) {
		hSubDivs = Defs.hSubDivs;
	}
	Axis.Normalize();
	if(!Axis.IsNormalized()) {
		Axis = Defs.Axis;
	}
} // cMeshConatainer::PlaneArgs::Validate

//-----------------------------------------------------------------------------
// cMeshConatainer::GenPlane
//-----------------------------------------------------------------------------
cMeshConatainer * cMeshConatainer::GenPlane(PlaneArgs Args) {
	Args.Validate();
	
	const int NPositionsTexCoords = (Args.wSubDivs + 1) * (Args.hSubDivs + 1);
	const int NNormals = (Args.TwoSided ? 2 : 1) * NPositionsTexCoords;
	const int NPolys = Args.wSubDivs * Args.hSubDivs * (Args.TwoSided ? 2 : 1);

	cVec3 W, H;
	Args.Axis.ToPerps(W, H);
	W.FixDenormals();
	H.FixDenormals();
	
	cMeshConatainer *Mesh = new cMeshConatainer;
	Mesh->SetName("Plane");

	// Positions && TexCoords:
	const float iwSubDivs = 1.0f / (float)Args.wSubDivs;
	const float ihSubDivs = 1.0f / (float)Args.hSubDivs;
	
	float w0 = - 0.5f * Args.Width;
	float wCur = w0;
	float hCur = 0.5f * Args.Height;
	float dw = Args.Width / (float)Args.wSubDivs;
	float dh = Args.Height / (float)Args.hSubDivs;
	int iw, ih;
	for(ih = 0; ih <= Args.hSubDivs; ih++) {
		for(iw = 0; iw <= Args.wSubDivs; iw++) {
			Mesh->GetPositions().Add(wCur * W + hCur * H);
			Mesh->GetTexCoords().Add(cVec2((float)iw * iwSubDivs, (float)ih * ihSubDivs));

			wCur += dw;
		}
		hCur -= dh;
		wCur = w0;
	}

	cAssert(Mesh->GetPositions().Count() == NPositionsTexCoords);
	cAssert(Mesh->GetTexCoords().Count() == NPositionsTexCoords);

	// Normals && Tangents:
	for(int iNormal = 0; iNormal < NNormals; iNormal++) {
		if(iNormal < NPositionsTexCoords) {
			Mesh->GetNormals().Add(Args.Axis);
			Mesh->GetTangents().Add(cVec<cVec3, 2>(W, H));
		} else { // TwoSided
			Mesh->GetNormals().Add(-Args.Axis);
			Mesh->GetTangents().Add(cVec<cVec3, 2>(W, -H));
		}
	}

	cAssert(Mesh->GetNormals().Count() == NNormals);
	cAssert(Mesh->GetTangents().Count() == NNormals);
	
	// Raw:
	for(ih = 0; ih < Args.hSubDivs; ih++) {
		for(iw = 0; iw < Args.wSubDivs; iw++) {
			const int i0 = (Args.wSubDivs + 1) * ih + iw;
			const int i1 = (Args.wSubDivs + 1) * (ih + 1) + iw;

			Mesh->GetRaw().Add(cVec3i(4, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i0));
			Mesh->GetRaw().Add(cVec3i(i1));
			Mesh->GetRaw().Add(cVec3i(i1 + 1));
			Mesh->GetRaw().Add(cVec3i(i0 + 1));

			if(Args.TwoSided) {
				Mesh->GetRaw().Add(cVec3i(4, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i0, i0, NPositionsTexCoords + i0));
				Mesh->GetRaw().Add(cVec3i(i0 + 1, i0 + 1, NNormals / 2 + i0 + 1));
				Mesh->GetRaw().Add(cVec3i(i1 + 1, i1 + 1, NNormals / 2 + i1 + 1));
				Mesh->GetRaw().Add(cVec3i(i1, i1, NNormals / 2 + i1));
			}
		}
	}

	cAssert(Mesh->GetPolyCount() == NPolys);

	return Mesh;
} // cMeshConatainer::GenPlane

//----------------------------------------------------------------------------------------------------------
// cMeshConatainer::GenPlaneHexagonal
//----------------------------------------------------------------------------------------------------------
cMeshConatainer * cMeshConatainer::GenPlaneHexagonal(const float Lx, const float Ly, const float Cell, const bool Noisy) {
	cAssert(Cell > 0.0f);

	cMeshConatainer *Mesh = new cMeshConatainer;
	Mesh->SetName("HexagonalPlane");

	// Positions:
	const int xCells = int(Lx / Cell), yCells = int(Ly / Cell);
	int ix, iy;
	for(iy = 0; iy <= yCells; iy++) {
		for(ix = 0; ix <= xCells; ix++) {
			Mesh->GetPositions().Add(cVec3((float)ix * Cell, float(iy) * Cell, 0.0f));
		}
	}
	for(iy = 0; iy < yCells; iy++) {
		for(ix = 0; ix < xCells; ix++) {
			Mesh->GetPositions().Add(cVec3((float)ix * Cell + Cell / 2.0f, float(iy) * Cell + Cell / 2.0f, 0.0f));
		}
	}
	
	int Shift = (xCells + 1) * (yCells + 1);
	for(int yt = 0; yt < yCells; yt++)
		for(int xt = 0; xt < xCells; xt++) {
			// Left:
			int i0 = yt * xCells + xt + Shift;
			int i1 = yt * (xCells + 1) + xt;
			int i2 = i1 + (xCells + 1);

			Mesh->GetRaw().Add(cVec3i(3, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i0, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i2, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i1, 0, 0));
			// Right:
			Mesh->GetRaw().Add(cVec3i(3, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i0, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i1 + 1, 0, 0));
			Mesh->GetRaw().Add(cVec3i(i2 + 1, 0, 0));
			if(0 == yt) { // Top cover:
				Mesh->GetRaw().Add(cVec3i(3, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i0, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i1, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i1 + 1, 0, 0));
			} else {
				int i4 = i0 - xCells;
				// Left - top:
				Mesh->GetRaw().Add(cVec3i(3, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i0, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i1, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i4, 0, 0));
				// Right - top:
				Mesh->GetRaw().Add(cVec3i(3, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i0, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i4, 0, 0));
				Mesh->GetRaw().Add(cVec3i(i1 + 1, 0, 0));
				if(yCells - 1 == yt) { // Bottom cover:
					Mesh->GetRaw().Add(cVec3i(3, 0, 0));
					Mesh->GetRaw().Add(cVec3i(i0, 0, 0));
					Mesh->GetRaw().Add(cVec3i(i2 + 1, 0, 0));
					Mesh->GetRaw().Add(cVec3i(i2, 0, 0));
				}
			}
	}

	if(Noisy) {
		const float h = 0.18f * Cell;
		for(int i = 0; i < Mesh->GetPositions().Count(); i++) {
			cVec3 &u = Mesh->GetPositions()[i];
			u.x += float(cMath::RandRange1() * h);
			u.y += float(cMath::RandRange1() * h);
			u.z += float(cMath::RandRange1() * h);
		}
	}

	return Mesh;
} // cMeshConatainer::GenPlaneHexagonal

//-----------------------------------------------------------------------------
// cMeshConatainer::FreeHashTable
//-----------------------------------------------------------------------------
void cMeshConatainer::FreeHashTable() const {
	for(int i = 0; i < m_HashTable.Count(); i++) {
		HashEntry *pEntry = m_HashTable[i];
		while(pEntry != NULL) {
			HashEntry *pNext = pEntry->pNext;
			delete pEntry;
			pEntry = pNext;
		}
	}
	m_HashTable.Free();
} // cMeshConatainer::FreeHashTable

cMeshConatainer::~cMeshConatainer(){
	for(int i=0;i<Morphs.Count();i++)delete(Morphs[i]);
}
}